package hibernate.hibernateInterface;

import java.util.*;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.*;

import hibernate.clientAccount.*;
import hibernate.billStream.*;
import hibernate.roomSystem.*;

public class RoomSystemHibernateInterface {

	protected RoomSystemHibernateInterface(){}
	
	public static Room getRoomByID(Long id,Session session) throws Exception
	{
		Room room = new Room();
		Criteria criteria = session.createCriteria(Room.class);
		Criterion criterion = Expression.eq("id",id);
		criteria = criteria.add(criterion);
		List resultList = criteria.list();
		if (resultList.size() == 0)
			throw new Exception("RoomNotFoundException");
		else if (resultList.size() > 1)
			throw new Exception("RoomOverlappingException");
		room = (Room)resultList.get(0);
		return room;
	}
	
	public static List getRoomsByTAF(Set concreteType,SizeAndFacilities SAF,int operator,Session session)
	{
		String queryScript = "from Room r,RoomState s where r.id = s.id and ";
		Object concreteTypeArray[] = concreteType.toArray(); 
		for (int i = 0;i < concreteType.size();i++){
			queryScript += "s.states like '%" + concreteTypeArray[i].toString() + "%' ";
			if(i != concreteType.size()-1)
				queryScript+=operator == 0 ? "or " : "and ";
		}
		Query query = session.createQuery(queryScript);
		LinkedList resultList = new LinkedList();
		resultList.addAll(query.list());
		for (int i = 0;i < resultList.size();i++)
		{
			if (resultList.get(i) instanceof Room)
			{
				Room room = (Room)resultList.get(i);
				if (!(room.getRoomType().getSizeAndFacilities().equals(SAF)))
					resultList.remove(i);
			}
			else
				resultList.remove(i);
		}
		return resultList;
	}
	
	public static List getRoomsByState(Set concreteType,Session session) throws Exception
	{
		String queryScript = "from Room r,RoomState s where r.id = s.id and ";
		Object concreteTypeArray[] = concreteType.toArray(); 
		for (int i = 0;i < concreteType.size();i++){
			queryScript += "s.states like '%" + concreteTypeArray[i].toString() + "%' ";
			if(i != concreteType.size()-1)
				queryScript += " and ";
		}
		System.out.println(queryScript);
		Query query = session.createQuery(queryScript);
		List resultList = query.list();
		if (resultList.size() == 0)
			throw new Exception("RoomNotFoundException");
		return resultList;
	}
	
	public static List getRoomsByTAF(Set concreteType,String SAF,Session session)
	{
		String queryScript = "from Room r,RoomState s on r.ID = s.ID where ";
		Object concreteTypeArray[] = concreteType.toArray(); 
		for (int i = 0;i < concreteType.size();i++)
			queryScript += "s.STATES like '%" + concreteTypeArray[i].toString() + "%' ";
		Query query = session.createQuery(queryScript);
		LinkedList resultList = new LinkedList();
		resultList.addAll(query.list());
		for (int i = 0;i < resultList.size();i++)
		{
			if (resultList.get(i) instanceof Room)
			{
				Room room = (Room)resultList.get(i);
				if (!(room.getRoomType().getSizeAndFacilities().equals(SAF)))
					resultList.remove(i);
			}
			else
				resultList.remove(i);
		}
		return resultList;
	}
	
	public static Room getRoomByRoomNumber(String roomNum,Session session) throws Exception
	{
		Room room = new Room();
		Criteria criteria = session.createCriteria(Room.class);
		Criterion criterion = Expression.eq("roomNumber", roomNum);
		criteria = criteria.add(criterion);
		List resultList = criteria.list();
		if (resultList.size() == 0)
			throw new Exception("RoomNotFoundException");
		else if (resultList.size() > 1)
			throw new Exception("RoomOverlappingException");
		room = (Room)resultList.get(0);
		return room;
	}
	
	public static List getRoomsBySAF(SizeAndFacilities saf,Session session) throws Exception
	{
		String queryScript = "from Room r,RoomType t where r.id = t.id and t.sizeAndFacilities = '" + saf.toString()+"'";
		Query query = session.createQuery(queryScript);
		List resultList = query.list();
		if (resultList.size() == 0)
			throw new Exception("RoomNotFoundException");
		return resultList;
	}
	
	public static List getRoomsByFacing(Facing facing,Session session) throws Exception
	{
		String queryScript = "from Room r,RoomType t where r.id = t.id and t.facing = '" + facing.toString()+"'";
		Query query = session.createQuery(queryScript);
		List resultList = query.list();
		if (resultList.size() == 0)
			throw new Exception("RoomNotFoundException");
		return resultList;
	}
	
	public static List getRoomsBySpeciality(Speciality speciality,Session session) throws Exception
	{
		String queryScript = "from Room r,RoomType t where r.id = t.id and t.speciality = '" + speciality.toString()+"'";
		Query query = session.createQuery(queryScript);
		List resultList = query.list();
		if (resultList.size() == 0)
			throw new Exception("RoomNotFoundException");
		return resultList;
	}
	
	public static List getRoomsByCondition(String sqlScript,Session session) throws Exception
	{
		Query query = session.createQuery(sqlScript);
		List resultList = query.list();
		if (resultList.size() == 0)
			throw new Exception("RoomNotFoundException");
		return resultList;
	}
	
	public static List getAllPartTimeRooms(Session session) throws Exception
	{
		String queryScript = "from Room r,RoomType t where r.id = t.id and t.partTimeAllowed = true";
		Query query = session.createQuery(queryScript);
		List resultList = query.list();
		if (resultList.size() == 0)
			throw new Exception("RoomNotFoundException");
		return resultList;
	}

	public static Room getRoomByConcreteBill(ConcreteBill bill,Session session) throws Exception
	{
		bill=(ConcreteBill)session.get(ConcreteBill.class,bill.getId());
		if(bill == null)
			return null;
		return bill.getAssociatedRoom();
	}
	
	private static List getChildOfBill(Bill bill)
	{
		LinkedList<Bill> tempBillList = new LinkedList<Bill>();
		LinkedList resultList = new LinkedList();
		tempBillList.add(bill);
		while (!tempBillList.isEmpty())
		{
			Bill tempBill = tempBillList.getFirst();
			tempBillList.removeFirst();
			if (tempBill instanceof ConcreteBill)
				resultList.add(tempBill);
			else
			{
				tempBillList.addAll(((MergedBill)tempBill).getBills());
			}
		}
		return resultList;
	}
	
	public static List getAllRoomsChildOfBill (Long billID,Session session)throws Exception
	{
		Criteria criteria = session.createCriteria(Bill.class);
		Criterion criterion = Expression.eq("id",billID);
		criteria = criteria.add(criterion);
		List resultList = criteria.list();
		if (resultList.size() == 0)
			throw new Exception("BillNotFoundException");
		else if (resultList.size() > 1)
			throw new Exception("BillOverlappingException");
		Bill bill = (Bill)resultList.get(0);
		List billList = getChildOfBill(bill);
		LinkedList roomList = new LinkedList();
		for (int i = 0;i < billList.size();i++)
		{
			roomList.add(((ConcreteBill)billList.get(i)).getAssociatedRoom());
		}
		return roomList;
	}
	
	public static Room getRoomAccordingToSingleClient(Long clientID,Session session)throws Exception
	{
		SingleClient client=(SingleClient)session.get(SingleClient.class,clientID);
		if(client == null)return null;
		if(client.getIsCurrentInHotel()){
			RoomState state=client.getCurrentRoom();
			if(state == null)
				return null;
			else return state.getRoom();
		}else return null;
		/*
		Room room = new Room();
		Criteria criteria = session.createCriteria(SingleClient.class);
		Criterion criterion = Expression.eq("id",clientID);
		criteria = criteria.add(criterion);
		List resultList = criteria.list();
		if (resultList.size() == 0)
			throw new Exception("ClientNotFoundException");
		else if (resultList.size() > 1)
			throw new Exception("ClientOverlappingException");
		room = ((SingleClient)resultList.get(0)).getCurrentRoom().getRoom();
		return room;
		*/
	}
	
	private static List getChildOfGroup(Group group)
	{
		LinkedList<AbstractClient> tempClientList = new LinkedList<AbstractClient>();
		LinkedList resultList = new LinkedList();
		tempClientList.add(group);
		while (!tempClientList.isEmpty())
		{
			AbstractClient client = tempClientList.getFirst();
			tempClientList.removeFirst();
			if (client instanceof SingleClient)
				resultList.add(client);
			else
			{
				tempClientList.addAll(((Group)client).getCustomerList());
			}
		}
		return resultList;
	}
	
	public static List getRoomsByOfGroup(Long groupID,Session session) throws Exception
	{
		Group group=(Group)session.get(Group.class,groupID);
		/*
		Criteria criteria = session.createCriteria(Group.class);
		Criterion criterion = Expression.eq("id",groupID);
		criteria = criteria.add(criterion);
		List resultList = criteria.list();
		if (resultList.size() == 0)
			throw new Exception("GroupNotFoundException");
		else if (resultList.size() > 1)
			throw new Exception("GroupOverlappingException");
		Group group = (Group)resultList.get(0);*/
		List clientList = getChildOfGroup(group);
		if(group == null)
			return new LinkedList();
		LinkedList roomList = new LinkedList();
		for (int i = 0;i < clientList.size();i++)
			roomList.add(((SingleClient)clientList.get(i)).getCurrentRoom());
		return roomList;
	}
	
	public static List getAllRooms(Session session) throws Exception
	{
		String queryScript = "from Room r";
		Query query = session.createQuery(queryScript);
		List resultList = query.list();
		if (resultList.size() == 0)
			throw new Exception("RoomNotFoundException");
		return resultList;
	}
	
	public static Set getAllServicesByRoomNumber(String roomNum,Session session)throws Exception
	{
		String queryScript = "from Room r where r.roomNumber = '" + roomNum+"'";
		Query query = session.createQuery(queryScript);
		List resultList = query.list();
		if (resultList.size() == 0)
			throw new Exception("RoomNotFoundException");
		else if (resultList.size() > 1)
			throw new Exception("RoomOverlappingException");
		RoomType roomType = (RoomType)resultList.get(0);
		return roomType.getServicesAvaliable();
	}
	
	public static ServiceWrapper getServiceByID (Long serviceWrapperID,Session session)throws Exception
	{
		return (ServiceWrapper)session.get(ServiceWrapper.class, serviceWrapperID);
		/*
		Criteria criteria = session.createCriteria(ServiceWrapper.class);
		Criterion criterion = Expression.eq("id",serviceWrapperID);
		criteria = criteria.add(criterion);
		List resultList = criteria.list();
		if (resultList.size() == 0)
			throw new Exception("ServiceNotFoundException");
		else if (resultList.size() > 1)
			throw new Exception("ServiceOverlappingException");
		ServiceWrapper service = (ServiceWrapper)resultList.get(0);
		return service;*/
	}
	
	public static ServiceCategory getCategoryByID(Long categoryID,Session session)throws Exception
	{
		return (ServiceCategory)session.get(ServiceCategory.class,categoryID);
		/*
		Criteria criteria = session.createCriteria(ServiceCategory.class);
		Criterion criterion = Expression.eq("id",categoryID);
		criteria = criteria.add(criterion);
		List resultList = criteria.list();
		if (resultList.size() == 0)
			throw new Exception("ServiceCategoryNotFoundException");
		else if (resultList.size() > 1)
			throw new Exception("ServiceCategoryOverlappingException");
		ServiceCategory serviceCategory = (ServiceCategory)resultList.get(0);
		return serviceCategory;*/
	}
	
	public static Set getAllServicesInCategory(Long categoryID,Session session)throws Exception
	{
		ServiceCategory cata=(ServiceCategory)session.get(ServiceCategory.class,categoryID);
		if(cata == null)
			return null;
		else return cata.getServicesIncluded();
		/*
		Criteria criteria = session.createCriteria(ServiceCategory.class);
		Criterion criterion = Expression.eq("id",categoryID);
		criteria = criteria.add(criterion);
		List resultList = criteria.list();
		if (resultList.size() == 0)
			throw new Exception("ServiceCategoryNotFoundException");
		else if (resultList.size() > 1)
			throw new Exception("ServiceCategoryOverlappingException");
		ServiceCategory serviceCategory = (ServiceCategory)resultList.get(0);
		return serviceCategory.getServicesIncluded();*/
	}
	
	public static List getAllServices(Session session)throws Exception
	{
		String queryScript = "from ServiceWrapper s";
		Query query = session.createQuery(queryScript);
		List resultList = query.list();
		if (resultList.size() == 0)
			throw new Exception("ServiceNotFoundException");
		return resultList;
	}
	
	public static List getAllCategories(Session session)throws Exception
	{
		String queryScript = "from ServiceCategory sc";
		Query query = session.createQuery(queryScript);
		List resultList = query.list();
		if (resultList.size() == 0)
			throw new Exception("ServiceCategoryNotFoundException");
		return resultList;
	}

}